package com.zyl.edthresholdtraining.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zyl.edthresholdtraining.common.AppConstant;
import com.zyl.edthresholdtraining.dto.UserInfoDTO;
import com.zyl.edthresholdtraining.entity.TimeConfigure;
import com.zyl.edthresholdtraining.entity.TimePartitionAllow;
import com.zyl.edthresholdtraining.mapper.TimePartitionAllowMapper;
import com.zyl.edthresholdtraining.service.TimeConfigureService;
import com.zyl.edthresholdtraining.service.TimePartitionAllowService;
import com.zyl.edthresholdtraining.service.UserInfoService;
import com.zyl.edthresholdtraining.service.UserTestResultService;
import com.zyl.edthresholdtraining.util.UuidUtil;
import com.zyl.edthresholdtraining.vo.BaseException;
import com.zyl.edthresholdtraining.vo.RichResult;
import com.zyl.edthresholdtraining.vo.UserTestResultVO;
import com.zyl.edthresholdtraining.vo.UserTestVO;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * @author zhangyulu
 * @description
 * @date 2020/7/31/031
 */
@Slf4j
@Controller
@RequestMapping(AppConstant.PROJECT_NAME)
public class UserInfoController {

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private TimeConfigureService timeConfigureService;

    @Autowired
    private TimePartitionAllowMapper timePartitionAllowMapper;

    @Autowired
    private UserTestResultService userTestResultService;

    @Autowired
    private TimePartitionAllowService timePartitionAllowService;
    /**被试测试次数限定*/
    private Integer testTimes;
    /**被试测试时间区间*/
    private String timePartition;
    /**被试测试时每个时间分区可以进行测试的时间(单位ms)*/
    private Long testTime;
    /**当前时间分区*/
    private String currentPartition;
    /** 当前时间*/
    private String currentDate;
    /** 图片切换时间*/
    private Integer changeImageTime;
    /** 测试图片总量*/
    private Integer imageTotalCount;
    /**
     * 1.添加被试信息，给被试返回相应的编号
     * 2.为该被试生成一个固定测试图片组合
    * */
    @ResponseBody
    @PostMapping("/add")
    @ApiOperation("添加被试信息")
    public RichResult<String> add(@RequestBody UserInfoDTO userInfoDTO) throws BaseException {
        String number = userInfoService.add(userInfoDTO);
        return new RichResult(number);
    }

    /**
     * 被试输入相应的标号进行训练
     * */
    @GetMapping("/train")
    @ApiOperation("跳到训练的的界面")
    public String train() {
        return "train";
    }

    /**
     * 被试输入相应的标号进行测试
    * */
    @GetMapping("/test")
    @ApiOperation("跳到训练的的界面")
    public String test() {
        return "test";
    }


    /** HttpSession session = request.getSession();
        Integer times = (Integer)session.getAttribute(AppConstant.MAX_TRAIN_TIMES+userId);
        if (times == null || times > 0) {
            if (times != null) {
                times--;
                session.setAttribute(AppConstant.MAX_TRAIN_TIMES+userId,times);
            } else {
                session.setAttribute(AppConstant.MAX_TRAIN_TIMES+userId,AppConstant.MAX_TRAIN_TIMES_VALUE-1);
            }
            try {
                List<UserTestVO> userTestContent = userInfoService.getUserTestContent(userId, request);
                model.addAttribute("userTestContent",userTestContent);
                model.addAttribute("userId",userId);
                model.addAttribute("changeImageTime",changeImageTime);
            } catch (Exception e) {
                log.error(e.getMessage());
            }
            return "trainTesting";
        }else {
            return "";
        }*/
    /**
    * 被试输入编号进行使用
    *   1.通过被试编号获取相应的图片组合信息
     *  2.将相应的组合信息返回给前端
     *  3.前端进行响应的测试
     * */
    @GetMapping("/train/login/{userId}")
    @ApiOperation("登入进行系统测试")
    public String train(@PathVariable("userId") String userId, HttpServletRequest request, Model model) throws Exception {
        init();
        boolean flag = adjudge1(userId, request);
        HttpSession session = request.getSession();
        if (flag) {
            Integer times = (Integer) session.getAttribute(AppConstant.MAX_TRAIN_TIMES + userId);
            if (times == null || times > 0) {
                if (times != null) {
                    times--;
                    session.setAttribute(AppConstant.MAX_TRAIN_TIMES + userId, times);
                } else {
                    session.setAttribute(AppConstant.MAX_TRAIN_TIMES + userId, testTimes - 1);
                }
                try {
                    List<UserTestVO> userTestContent = userInfoService.getUserTestContent(userId, request);
                    model.addAttribute("userTestContent", userTestContent);
                    model.addAttribute("userId", userId);
                    model.addAttribute("changeImageTime", changeImageTime);
                    model.addAttribute("testTimes", testTimes);
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
                return "trainTesting";
            } else {
                modify(userId,request);
                model.addAttribute("userId",userId);
                    //做条件判断如果没有测完指定的数据量
                String dateMark = timePartitionAllowService.getDateMark(userId);
                if (StringUtils.isEmpty(dateMark)) {
                    log.info("=============标记数据丢失===============");
                    log.error("=============标记数据丢失=============");
                } else {
                    TimePartitionAllow timePartitionAllow = this.timePartitionAllowService.getTimePartitionAllowService(userId, AppConstant.TIME_PARTITION_TRAIN, dateMark);
                    //获取被试该时间区域的平均正确率以及平均反应时
                    if (timePartitionAllow == null) {
                        model.addAttribute("msg", "你的上次测试出现问题，请按规则进行测试！！！");
                        log.info("=============出现空指针!!!=============");
                        log.error("=============出现空指针!!!=============");
                    } else {
                        UserTestResultVO timePartitionTotalAvg = userTestResultService.getTimePartitionTotalAvg(timePartitionAllow.getTimePartitionUuid(), request);
                        model.addAttribute("timePartitionTotalAvg", timePartitionTotalAvg);
                    }
                }
                return "trainTip";
            }
        }else {
            modify(userId,request);
            model.addAttribute("userId",userId);
                //做条件判断如果没有测完指定的数据量
            String dateMark = timePartitionAllowService.getDateMark(userId);
            if (StringUtils.isEmpty(dateMark)) {
                log.info("=============标记数据丢失===============");
                log.error("=============标记数据丢失=============");
            } else {
                TimePartitionAllow timePartitionAllow = this.timePartitionAllowService.getTimePartitionAllowService(userId, AppConstant.TIME_PARTITION_TRAIN, dateMark);
                //获取被试该时间区域的平均正确率以及平均反应时
                if (timePartitionAllow == null) {
                    model.addAttribute("msg", "你的上次测试出现问题，请按规则进行测试！！！");
                    log.info("=============出现空指针!!!=============");
                    log.error("=============出现空指针!!!=============");
                } else {
                    UserTestResultVO timePartitionTotalAvg = userTestResultService.getTimePartitionTotalAvg(timePartitionAllow.getTimePartitionUuid(), request);
                    model.addAttribute("timePartitionTotalAvg", timePartitionTotalAvg);
                }
            }
            return "trainTip";
        }

    }

    private void modify(String userId,HttpServletRequest request) {
        init();
        request.getSession().setAttribute(AppConstant.MAX_TRAIN_TIMES + userId, testTimes);
        //修改记录表
        request.getSession().setAttribute(AppConstant.TRAIN_TIME_MARK + userId, null);
    }

    /**
     * 被试输入编号进行使用
     *  1.通过被试编号获取相应的图片组合信息
     *  2.将相应的组合信息返回给前端
     *  3.前端进行响应的测试test·
     *
     *  后续这里配置学习可以测试的时间区间
     *      现在先不写死，后面开放一个配置接口
     * */
    @GetMapping("/test/login/{userId}")
    @ApiOperation("登入进行系统测试")
    public String test(@PathVariable("userId") String userId, HttpServletRequest request, Model model) {
        /**
         * 判断是否可以进行测试.
         * 1.先获取配置信息表
         * 2.判断是否在测试时间段
         * 3.判断是否超过配置次数
         * */
        init();
        boolean flag = adjudge(userId,request);
        if (flag) {
            HttpSession session = request.getSession();
            Integer times = (Integer)session.getAttribute(AppConstant.MAX_TEST_TIMES+userId);
            if (times == null || times > 0) {
                if (times != null) {
                    times--;
                    session.setAttribute(AppConstant.MAX_TEST_TIMES+userId,times);
                } else {
                    session.setAttribute(AppConstant.MAX_TEST_TIMES+userId,testTimes-1);
                }
                try {
                    List<UserTestVO> userTestContent = userInfoService.getUserTestContent(userId, request);
                    model.addAttribute("userTestContent",userTestContent);
                    model.addAttribute("userId",userId);
                    model.addAttribute("changeImageTime",changeImageTime);
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
                return "testing";
            }else {
                if (StringUtils.isEmpty(currentPartition)) {
                    model.addAttribute("msg","当前时间段没有进行测试！");
                } else {
                    TimePartitionAllow timePartitionAllow= this.timePartitionAllowService.getTimePartitionAllowService(userId, currentPartition,currentDate);
                    //获取被试该时间区域的平均正确率以及平均反应时
                    if (timePartitionAllow == null) {
                        log.info("Null指针异常");
                    } else {
                        UserTestResultVO timePartitionTotalAvg = userTestResultService.getTimePartitionTotalAvg(timePartitionAllow.getTimePartitionUuid(), request);
                        model.addAttribute("timePartitionTotalAvg",timePartitionTotalAvg);
                    }
                }
                return "tip";
            }
        }else {
            //获取该用户这一个时间区域测试的最终的测评数据  测试的组数
            if (StringUtils.isEmpty(currentPartition)) {
                model.addAttribute("msg","当前时间段没有进行测试！");
            } else {
                TimePartitionAllow timePartitionAllow= this.timePartitionAllowService.getTimePartitionAllowService(userId, currentPartition,currentDate);
                //获取被试该时间区域的平均正确率以及平均反应时
                if (timePartitionAllow == null) {
                    log.info("Null指针异常");
                } else {
                    UserTestResultVO timePartitionTotalAvg = userTestResultService.getTimePartitionTotalAvg(timePartitionAllow.getTimePartitionUuid(), request);
                    model.addAttribute("timePartitionTotalAvg",timePartitionTotalAvg);
                }
            }
            return "timeTip";
        }
    }

    private boolean adjudge(String userId,HttpServletRequest request) {
        //获取当前时间是几点钟
        Date date = new Date();
        SimpleDateFormat f = new SimpleDateFormat("HH");
        String _hour = f.format(date);
        if (_hour.startsWith("0")) {
            _hour = _hour.substring(1);
        }
        int hour = Integer.parseInt(_hour);
        int hourTime = hour + 8;
        if (hourTime > 24) {
            hourTime = hourTime - 24;
        }
        log.info("===========获取到的时间："+hourTime+"===============");
        log.debug("===========获取到的时间："+hourTime+"===============");
        String[] partition = timePartition.split(";");
        for (int i = 0; i < partition.length; i++) {
            String partitionT = partition[i];
            String[] time = partitionT.split("-");
            if (Integer.parseInt(time[0])<= hourTime && hourTime < Integer.parseInt(time[1])) {
                //判断是否超过了该阶段的时间区间 使用一张表进行维护
                boolean flag = getTimePartitionAllow(partitionT, userId,request,2);
                currentPartition = partitionT;
                return flag;
            }
        }
        return false;
    }

    private boolean adjudge1(String userId,HttpServletRequest request) throws Exception {
        return getTimePartitionAllow1(AppConstant.TIME_PARTITION_TRAIN, userId,request,1);
    }

    private boolean getTimePartitionAllow1(String partitionT,String _userId,HttpServletRequest request,Integer type) throws Exception {
        HttpSession session = request.getSession();
        Long userId = Long.parseLong(_userId);
        QueryWrapper<TimePartitionAllow> queryWrapper = new QueryWrapper<>();
        String trainDateMark = (String)session.getAttribute(AppConstant.TRAIN_TIME_MARK+_userId);
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date();
        if (StringUtils.isEmpty(trainDateMark)) {
            trainDateMark = f.format(date);
            currentDate = trainDateMark;
            session.setAttribute(AppConstant.TRAIN_TIME_MARK+_userId,trainDateMark);
        } else {
            Date parse = f.parse(trainDateMark);
            Date date1 = new Date();
            long startTime = parse.getTime();
            long endTime = date1.getTime();
            if (endTime - startTime <= testTime) {
                currentDate = trainDateMark;
            }
        }
        queryWrapper.eq("user_id",userId).eq("time_partition",partitionT)
                .eq("date_mark",trainDateMark);
        List<TimePartitionAllow> timePartitionAllowList = timePartitionAllowMapper.selectList(queryWrapper);
        TimePartitionAllow timePartitionAllow = new TimePartitionAllow();
        if (CollectionUtils.isEmpty(timePartitionAllowList)) {
            long startTime = System.currentTimeMillis();
            log.info("该被试{}在该时间区间{}开始测试时间{}",userId,partitionT,startTime);
            //保存这个时间
            String uuid = UuidUtil.getUUID();
            session.setAttribute(AppConstant.USER_ID+type+_userId,uuid);
            timePartitionAllow.setTimePartition(partitionT);
            timePartitionAllow.setUserId(userId);
            timePartitionAllow.setStartTime(startTime);
            timePartitionAllow.setTimePartitionUuid(uuid);
            timePartitionAllow.setDateMark(currentDate);
            timePartitionAllowMapper.insert(timePartitionAllow);
            currentPartition = partitionT;
            return true;
        } else {
            long endTime = System.currentTimeMillis();
            timePartitionAllow = timePartitionAllowList.get(0);
            //判断时间是否大于该时间区域允许测试的时间
            Long startTime = timePartitionAllow.getStartTime();
            session.setAttribute(AppConstant.USER_ID+type+_userId,timePartitionAllow.getTimePartitionUuid());
            //并且给该段区间设置同一个Id 使用uuid 并使用session进行存储
            if (endTime - startTime > this.testTime) {
                log.info("该被试{}在该时间区间{}开始测试时间{}结束测试时间{},已超过指定的时间区间10分钟",userId,partitionT,startTime,endTime);
                //更新记录表信息
                endTime = startTime + this.testTime;
                timePartitionAllow.setEndTime(endTime);
                timePartitionAllow.setTestTime(this.testTime);
                timePartitionAllowMapper.updateById(timePartitionAllow);
                return false;
            }else {
                timePartitionAllow.setEndTime(endTime);
                timePartitionAllow.setUserId(userId);
                timePartitionAllow.setTestTime(endTime - startTime);
                timePartitionAllowMapper.updateById(timePartitionAllow);
                return true;
            }
        }
    }


    private boolean getTimePartitionAllow(String partitionT,String _userId,HttpServletRequest request,Integer type) {
        HttpSession session = request.getSession();
        Long userId = Long.parseLong(_userId);
        QueryWrapper<TimePartitionAllow> queryWrapper = new QueryWrapper<>();
        Date date = new Date();
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
        String dateMark = f.format(date);
        currentDate = dateMark;
        queryWrapper.eq("user_id",userId).eq("time_partition",partitionT)
                                .eq("date_mark",dateMark);
        List<TimePartitionAllow> timePartitionAllowList = timePartitionAllowMapper.selectList(queryWrapper);
        TimePartitionAllow timePartitionAllow = new TimePartitionAllow();
        if (CollectionUtils.isEmpty(timePartitionAllowList)) {
            long startTime = System.currentTimeMillis();
            log.info("该被试{}在该时间区间{}开始测试时间{}",userId,partitionT,startTime);
            //保存这个时间
            String uuid = UuidUtil.getUUID();
            session.setAttribute(AppConstant.USER_ID+type+_userId,uuid);
            timePartitionAllow.setTimePartition(partitionT);
            timePartitionAllow.setUserId(userId);
            timePartitionAllow.setStartTime(startTime);
            timePartitionAllow.setTimePartitionUuid(uuid);
            timePartitionAllow.setDateMark(dateMark);
            timePartitionAllowMapper.insert(timePartitionAllow);
            currentPartition = partitionT;
            return true;
        } else {
            long endTime = System.currentTimeMillis();
            timePartitionAllow = timePartitionAllowList.get(0);
            //判断时间是否大于该时间区域允许测试的时间
            Long startTime = timePartitionAllow.getStartTime();
            session.setAttribute(AppConstant.USER_ID+type+_userId,timePartitionAllow.getTimePartitionUuid());
            //并且给该段区间设置同一个Id 使用uuid 并使用session进行存储
            if (endTime - startTime > this.testTime) {
                log.info("该被试{}在该时间区间{}开始测试时间{}结束测试时间{},已超过指定的时间区间10分钟",userId,partitionT,startTime,endTime);
                //更新记录表信息
                endTime = startTime + this.testTime;
                timePartitionAllow.setEndTime(endTime);
                timePartitionAllow.setTestTime(this.testTime);
                timePartitionAllowMapper.updateById(timePartitionAllow);
                return false;
            }else {
                timePartitionAllow.setEndTime(endTime);
                timePartitionAllow.setUserId(userId);
                timePartitionAllow.setTestTime(endTime - startTime);
                timePartitionAllowMapper.updateById(timePartitionAllow);
                return true;
            }
        }
    }

    private void init() {
        List<TimeConfigure> list = timeConfigureService.list();
        if (CollectionUtils.isEmpty(list)) {
            throw new BaseException("时间配置信息出错！");
        }
        TimeConfigure timeConfigure = list.get(0);
        testTimes = timeConfigure.getUserTestTimes();
        timePartition = timeConfigure.getTimePartition();
        testTime = timeConfigure.getTestTime() * 60 * 1000L;
        changeImageTime = timeConfigure.getChangeImageTime() == null ? 500 : timeConfigure.getChangeImageTime();
        imageTotalCount = testTimes * 10;
    }

    @GetMapping("/testing")
    public String testing() {
        return "testing";
    }

    @GetMapping("/index")
    @ApiOperation("首页")
    public String index() {
        return "index";
    }

    @GetMapping("/error")
    @ApiOperation("错误页面")
    public String error() {
        return "error";
    }





}
